package mqtt2lora

import (
	"encoding/base64"
	"encoding/json"
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelAPI"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelParam"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelRestfulNotify"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/ChanSyncObj"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Reflect"
	mqtt "github.com/eclipse/paho.mqtt.golang"
	"go-fox-edge-channel-mqtt-lora/channelEvent"
	"strings"
)

type mqttHandler struct {
	clientId string
	topic    string
	router   map[string]interface{}
}

func (e *mqttHandler) Handler() mqtt.MessageHandler {
	return func(client mqtt.Client, msg mqtt.Message) {
		payload := make(map[string]interface{})
		err := json.Unmarshal(msg.Payload(), &payload)
		if err != nil {
			return
		}

		// 解析数据
		gatewayEUI, devEUI, data, err := e.paserMessage(msg.Topic(), payload)
		if err != nil {
			return
		}

		// 发出创建通道的消息：按照星纵物联的说法，fPort在下行方向，必须强制填写为85的系统端口
		e.CreateChannel(gatewayEUI, devEUI, 85)

		// 通知信息到达
		if ChanSyncObj.IsWaiting(devEUI) {
			// 问答类型：正在处于问答状态，通知数据到达
			ChanSyncObj.Notify(devEUI, data)
		} else {
			// 主动上报：主动上报数据
			message := make(map[string]interface{})
			message["gatewayEUI"] = gatewayEUI
			message["devEUI"] = devEUI
			message["data"] = data

			channelEvent.List.Notify(message)

			// 向API框架发出信号：有数据需要上报了，调用PopAll()吧
			channelAPI.Service.NotifyReport()
		}
	}
}

func (e *mqttHandler) paserMessage(topic string, payload map[string]interface{}) (gatewayEUI, devEUI string, data interface{}, err error) {
	for _, msgFmt := range Client.fmts {
		// 步骤1：取出devEUI
		devEUI = e.paserDevEUI(payload, msgFmt.devEUIKey)
		if devEUI == "" {
			continue
		}

		// 步骤2：取出gatewayEUI
		gatewayEUI = e.paserGateWayEUI(topic, msgFmt.gatewayEUIPrefix, msgFmt.gatewayEUISuffix)

		// 步骤3：取出data
		data, err = e.paserData(payload, msgFmt.dataKey, msgFmt.dataFmt)
		if err != nil {
			continue
		}

		return gatewayEUI, devEUI, data, nil
	}

	return "", "", nil, errors.New("找不到匹配的格式")
}

func (e *mqttHandler) paserGateWayEUI(topic string, gatewayEUIPrefix, gatewayEUISuffix string) string {
	gatewayEUI := topic
	if gatewayEUIPrefix != "" && strings.HasPrefix(topic, gatewayEUIPrefix) {
		gatewayEUI = gatewayEUI[len(gatewayEUIPrefix):]
	}
	if gatewayEUISuffix != "" && strings.HasSuffix(topic, gatewayEUISuffix) {
		gatewayEUI = gatewayEUI[:len(gatewayEUI)-len(gatewayEUISuffix)]
	}
	if gatewayEUI == topic {
		return ""
	}

	return gatewayEUI
}

func (e *mqttHandler) paserData(payload map[string]interface{}, dataKey, dataFmt string) (interface{}, error) {
	// 检查：dataKey的格式
	if dataKey == "" || !strings.HasPrefix(dataKey, "/") {
		return nil, errors.New("dataKey的格式不正确")
	}

	// 拆解为path格式
	keys := strings.Split(dataKey, "/")
	path := make([]interface{}, 0)
	for idx, val := range keys {
		if idx == 0 {
			continue
		}
		path = append(path, val)
	}

	if dataFmt == "base64" {
		if dataKey == "/" {
			return nil, errors.New("base64的data，必须指明具体的字段路径")
		}

		// 取出具体的数据
		val, _ := Map.GetValue(payload, path...)
		if val == nil || !Reflect.IsString(val) {
			return nil, errors.New("base64的data，必须是字符串格式")
		}

		return base64.StdEncoding.DecodeString(val.(string))
	}
	if dataFmt == "json" {
		// "/"的场景
		if dataKey == "/" {
			return payload, nil
		} else {
			val, _ := Map.GetValue(payload, path...)
			if val == nil || !Reflect.IsMap(val) {
				return nil, errors.New("json的data，必须是map格式")
			}

			return val, nil
		}
	}

	return nil, errors.New("bas找不到匹配的格式解析")
}

func (e *mqttHandler) paserDevEUI(payload map[string]interface{}, devEUIKey string) string {
	// 检查：devEUIKey的格式
	if devEUIKey == "" || !strings.HasPrefix(devEUIKey, "/") {
		return ""
	}

	// 拆解为path格式
	keys := strings.Split(devEUIKey, "/")
	path := make([]interface{}, 0)
	for idx, val := range keys {
		if idx == 0 {
			continue
		}
		path = append(path, val)
	}
	if len(path) == 0 {
		return ""
	}

	// 取出具体的数据
	val, _ := Map.GetValue(payload, path...)
	if val == nil || !Reflect.IsString(val) {
		return ""
	}

	return val.(string)
}

func (e *mqttHandler) CreateChannel(gatewayEUI, devEUI string, fport int) {
	// 检测：是否输入了通道名称前缀
	if gatewayEUI == "" || devEUI == "" {
		return
	}

	// 格式化名称
	chnName := "mqtt-lora-" + devEUI

	// 检查：该名称的实体是否已经存在
	if channelParam.GetChannelEntity(chnName) != nil {
		return
	}

	// 填写通道参数
	channelParam := make(map[string]interface{})
	channelParam["devEUI"] = devEUI
	channelParam["gatewayEUI"] = gatewayEUI
	channelParam["fport"] = fport

	// 发出消息
	channelRestfulNotify.CreateChannel(chnName, channelParam)
}
